﻿
Imports std
#Const predict = True

Public Class app
    Inherits iParseable

    Public Const functionSeparator As Char = character.semicolon
    Private Shared ELPMISAPP_INVOKE_TIMETICKS As Int64

    Shared Sub New()
        ELPMISAPP_INVOKE_TIMETICKS = counter.registerAverageAndLastAverage("ELPMISAPP_INVOKE_TIMETICKS")
    End Sub

    Protected Friend Shared Function _isMeaningfulMark(ByVal c As Char) As Boolean
        Return isseparator(c)
    End Function

    Private functions As vector(Of [function]) = Nothing

    'for inherit classes
    Protected Sub New(ByVal ifuncs As vector(Of [function]))
        assert(Not ifuncs Is Nothing, "ifuncs is nothing.")
        functions = ifuncs
    End Sub

    Private Function contextpool() As iContextpool
        Return context.contextpool()
    End Function

    Private Function _clear(ByVal ctx As context) As Boolean
        ctx.clear()
        Return True
    End Function

    Private Function invoke(ByVal startFunctionName As String, _
                            ByVal ctx As context, _
                            Optional ByVal parameters As iParameters = Nothing, _
                            Optional ByRef rtn As bare_variable = Nothing) As Boolean
        Dim startticks As Int64
        startticks = Now.Ticks()
        assert(Not ctx Is Nothing, "ctx is nothing.")

        Dim i As Int64
        For i = 0 To functions.size() - 1
            ctx.insertFunction(functions(i))
        Next
        Dim rst As Boolean
        Try
            rst = ctx.invoke(startFunctionName, parameters, rtn)
        Catch ex As Threading.ThreadAbortException
            raiseError("thread abort.", errorHandle.errorType.warning)
            rst = True
        End Try

        counter.increase(ELPMISAPP_INVOKE_TIMETICKS, Now.Ticks() - startticks)
        Return rst
    End Function

    Public Function invoke(ByVal startFunctionName As String, _
                           Optional ByVal parameters As iParameters = Nothing, _
                           Optional ByRef rtn As bare_variable = Nothing) As Boolean
        Dim index As Int64 = iContextpool.invalidIndex
        Dim ctx As context = Nothing
        If Not contextpool().getfree(index, ctx) Then
            raiseError("do not have free context in context pool.", errorHandle.errorType.exclamation)
            Return False
        End If
        Return invoke(startFunctionName, ctx, parameters, rtn) And _clear(ctx) And contextpool().release(index)
    End Function

    Public Function invokeShared(ByVal startFunctionName As String, _
                                 Optional ByVal parameters As iParameters = Nothing, _
                                 Optional ByRef rtn As bare_variable = Nothing) As Boolean
        Return invoke(startFunctionName, sharedContext, parameters, rtn)
    End Function

    Private Shared Function isseparator(ByVal c As Char) As Boolean
        Return c = functionSeparator
    End Function

    Private Shared Function isnotspace(ByVal c As Char) As Boolean
        Return Not isspace(c)
    End Function

    Protected Shared Function parseImpl(ByVal input As String, ByRef index As Int64, _
                                        ByRef output As vector(Of [function]), _
                                        ByVal needPredictOutput As Boolean) As Boolean
#If predict Then
        predict(input)
        If needPredictOutput Then
            writefile(combinepath(filesystem.temppath(), strleft(createGUID(), 8) + ".predict.lpms"), input)
        End If
#End If
        Dim functions As vector(Of [function]) = Nothing
        functions = New vector(Of [function])()
        Dim func As [function] = Nothing
        While [function].parse(input, index, func)
            functions.push_back(func)
            While token(input, index, Nothing, AddressOf isseparator, AddressOf [false])
            End While
        End While

        'no other valid characters later
        If Not token(input, index, Nothing, AddressOf isnotspace, AddressOf [false]) Then
            output = functions
            value.assert_ignore()
            Return True
        Else
            writeparseerror(input)
            Return False
        End If
    End Function

    Protected Shared Function parseImpl(ByVal input As String, ByRef index As Int64, _
                                        ByRef output As vector(Of [function])) As Boolean
        Return parseImpl(input, index, output, isdebugmode())
    End Function

    Protected Shared Function parseImpl(ByVal input As String, ByRef index As Int64, ByRef output As app) As Boolean
        Dim functions As vector(Of [function]) = Nothing
        If parseImpl(input, index, functions) Then
            output = New app(functions)
            Return True
        Else
            Return False
        End If
    End Function

    Protected Overrides Sub setsource(ByVal script As String, ByVal start As Long, ByVal [end] As Long)
        setsourceImpl(strleft(script, 64), start, [end])
    End Sub

    Public Shared Function parse(ByVal input As String, ByRef index As Int64, ByRef output As app) As Boolean
        Return parsebase(input, index, output, AddressOf parseImpl)
    End Function

    Public Shared Function parse(ByVal input As String, ByRef output As app) As Boolean
        Return parse(input, 0, output)
    End Function
End Class
